package com.spring.raft.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.spring.raft.websocket.WebSocketServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

@Service
public class RaftNodeService {

    private final int nodeId = new Random().nextInt(100);
    private final AtomicInteger currentTerm = new AtomicInteger(0);
    private int votedFor = -1;
    private int votesReceived = 0;
    private boolean isLeader = false;

    @Autowired
    private WebSocketServer webSocketServer;

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Scheduled(fixedDelay = 5000)
    public void checkElectionTimeout() {
        if (!isLeader) {
            System.out.println("⏳ 超时，开始新一轮选举...");
            startElection();
        }
    }

    private void startElection() {
        currentTerm.incrementAndGet();
        votedFor = nodeId;
        votesReceived = 1;

        var request = new RaftRequest("RequestVote", currentTerm.get(), nodeId);

        try {
            String message = objectMapper.writeValueAsString(request);
            webSocketServer.broadcast(message);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void processRaftRequest(RaftRequest request) {
        if ("RequestVote".equals(request.type)) {
            handleVoteRequest(request);
        } else if ("VoteGranted".equals(request.type)) {
            handleVoteGranted(request);
        } else if ("AppendEntries".equals(request.type)) {
            handleAppendEntries(request);
        }
    }

    private void handleVoteRequest(RaftRequest request) {
        if (request.term > currentTerm.get()) {
            currentTerm.set(request.term);
            votedFor = request.nodeId;

            var response = new RaftRequest("VoteGranted", currentTerm.get(), nodeId);

            try {
                String message = objectMapper.writeValueAsString(response);
                webSocketServer.broadcast(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private void handleVoteGranted(RaftRequest request) {
        if (request.term == currentTerm.get()) {
            votesReceived++;
            if (votesReceived > 1) {
                becomeLeader();
            }
        }
    }

    private void handleAppendEntries(RaftRequest request) {
        if (request.term >= currentTerm.get()) {
            currentTerm.set(request.term);
            isLeader = false;
            System.out.println("📩 Received heartbeat from Leader " + request.nodeId);
        }
    }

    private void becomeLeader() {
        isLeader = true;
        System.out.println("🏆 " + nodeId + " 成为 Leader!");
        sendHeartbeats();
    }

    @Scheduled(fixedRate = 3000)
    public void sendHeartbeats() {
        if (isLeader) {
            var heartbeat = new RaftRequest("AppendEntries", currentTerm.get(), nodeId);
            try {
                String message = objectMapper.writeValueAsString(heartbeat);
                webSocketServer.broadcast(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static class RaftRequest {
        public String type;
        public int term;
        public int nodeId;

        public RaftRequest(String type, int term, int nodeId) {
            this.type = type;
            this.term = term;
            this.nodeId = nodeId;
        }
    }
}
